/**
  ******************************************************************************
  * @file    zb32l03x_hal_i2s.c
  * @author  MCD Application Team
  * @Version V2.0.0
  * @Date    2022/08/23
  * @brief
  * @endverbatim
  ******************************************************************************
  */

#include "zb32l03x_hal.h"

#if defined(HAL_I2S_MODULE_ENABLED)

/** @addtogroup I2S
  * @brief I2S HAL module driver.
  * @{
  */

//=============================================================================
//                  Constant Definition
//=============================================================================

//=============================================================================
//                  Macro Definition
//=============================================================================

//=============================================================================
//                  Structure Definition
//=============================================================================

//=============================================================================
//                  Global Data Definition
//=============================================================================

//=============================================================================
//                  Private Function Definition
//=============================================================================

static void
_I2S_Transmit_IT(
    I2S_HandleTypeDef *pHI2s)
{
    /* Transmit data */
    pHI2s->Instance->DR = (*pHI2s->pTxBuffPtr);
    pHI2s->pTxBuffPtr++;
    pHI2s->TxXferCount--;

    if (pHI2s->TxXferCount == 0U)
    {
        /* Disable TXE and ERR interrupt */
        CLEAR_BIT(pHI2s->Instance->CR2,I2S_IT_TXE | I2S_IT_ERR);

        pHI2s->State = HAL_I2S_STATE_READY;
        /* Call user Tx complete callback */
        HAL_I2S_TxCpltCallback(pHI2s);
    }
}

static void
_I2S_Receive_IT(
    I2S_HandleTypeDef *pHI2s)
{
    /* Receive data */
    (*pHI2s->pRxBuffPtr) = (uint16_t)pHI2s->Instance->DR;
    pHI2s->pRxBuffPtr++;
    pHI2s->RxXferCount--;

    if (pHI2s->RxXferCount == 0U)
    {
        __HAL_I2S_DISABLE(pHI2s);
        /* Disable RXNE and ERR interrupt */
        CLEAR_BIT(pHI2s->Instance->CR2,I2S_IT_RXNE | I2S_IT_ERR);

        pHI2s->State = HAL_I2S_STATE_READY;
        /* Call user Rx complete callback */
        HAL_I2S_RxCpltCallback(pHI2s);
    }
}


static HAL_StatusTypeDef
_I2S_WaitFlagStateUntilTimeout(
    I2S_HandleTypeDef   *pHI2s,
    uint32_t            Flag,
    FlagStatus          State,
    uint32_t            Timeout)
{
    uint32_t tickstart = 0;

    tickstart = HAL_GetTick();

    /* Waiting until flag */
    while (((__HAL_I2S_GET_FLAG(pHI2s, Flag)) ? SET : RESET) != State)
    {
        if (Timeout == HAL_MAX_DELAY ||
            (Timeout && (HAL_GetTick() - tickstart) < Timeout))
            continue;

        pHI2s->State = HAL_I2S_STATE_READY;

        return HAL_TIMEOUT;
    }
    return HAL_OK;
}
static HAL_StatusTypeDef
_I2S_DMA_Config(
    HAL_DMA_Handle_TypeDef          *hdma,
    HAL_DMA_Channel_TypeDef         channel_id,
    HAL_DMA_Descriptor_Cfg_TypeDef  *pDescriptorCfg)
{
    HAL_DMA_Xfer_Cfg_TypeDef    transfer_cfg;
    HAL_StatusTypeDef           status = HAL_OK;

    status = HAL_DMA_Set_Descriptor(hdma, channel_id, pDescriptorCfg, 0);
    if( status != HAL_OK )
        return HAL_ERROR;

    // Start DMA
    transfer_cfg.is_immediate = 0;
    transfer_cfg.mode         = HAL_DMA_MODE_BASIC;
    transfer_cfg.type         = DMA_DESCRIPTOR_TYPE_PRIMARY;
    transfer_cfg.timeout      = -1;
    status = HAL_DMA_Channel_Sart(hdma, channel_id, &transfer_cfg);
    if( status != HAL_OK )  return HAL_ERROR;

    return HAL_OK;
}
//=============================================================================
//                  Public Function Definition
//=============================================================================

/**
  * @brief  Initializes the I2S according to the specified parameters
  *         in the I2S_InitTypeDef and create the associated handle.
  * @param  pHI2s : I2S handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_I2S_Init(I2S_HandleTypeDef *pHI2s)
{
    uint32_t i2sdiv = 0;
    uint32_t i2sodd = 0;
    uint32_t packetlength = 0;
    uint32_t tmp = 0;
    uint32_t i2sclk = 0;

    assert_param(IS_I2S_ALL_INSTANCE(pHI2s->Instance));
    assert_param(IS_I2S_MODE(pHI2s->Init.Mode));
    assert_param(IS_I2S_STANDARD(pHI2s->Init.Standard));
    assert_param(IS_I2S_DATA_FORMAT(pHI2s->Init.DataFormat));
    assert_param(IS_I2S_MCLK_OUTPUT(pHI2s->Init.MCLKOutput));
    assert_param(IS_I2S_AUDIO_FREQ(pHI2s->Init.AudioFreq));
    assert_param(IS_I2S_CPOL(pHI2s->Init.CPOL));

    if (!pHI2s)
        return HAL_ERROR;

    if (pHI2s->State == HAL_I2S_STATE_RESET)
    {
        pHI2s->Lock = HAL_UNLOCKED;
        HAL_I2S_MspInit(pHI2s);
    }

    pHI2s->State = HAL_I2S_STATE_BUSY;

    /* Reset I2SCFGR & I2SPR register */
    pHI2s->Instance->I2SCFGR = 0x0000U;
    pHI2s->Instance->I2SPR = 0x0002U;

    /*I2SPR: I2SDIV and ODD Calculation, if the requested audio frequency is not the default. */
    if (pHI2s->Init.AudioFreq == I2S_AUDIOFREQ_DEFAULT)
    {
        /* Set the default values */
        i2sdiv = 2U;
        i2sodd = 0U;
    }
    else
    {
        /* Check the frame length, in I2S standard packet lenght is multiplied by 2*/
        if (pHI2s->Init.DataFormat == I2S_DATAFORMAT_16B)
        {
            packetlength = 16U;
        }
        else
        {
            packetlength = 32U;
        }

        if (pHI2s->Init.Standard <= I2S_STANDARD_LSB)
        {
            packetlength = packetlength * 2U;
        }

        /* Compute the Real divider depending on the MCLK output state, with a floating point */
        i2sclk = HAL_RCC_GetSysClockFreq();
        if (pHI2s->Init.MCLKOutput == I2S_MCLKOUTPUT_ENABLE)
        {
            /* MCLK output is enabled */
            if (pHI2s->Init.DataFormat != I2S_DATAFORMAT_16B)
            {
                tmp = (uint32_t)(((((i2sclk / (packetlength * 4U)) * 10U) / pHI2s->Init.AudioFreq)) + 5U);
            }
            else
            {
                tmp = (uint32_t)(((((i2sclk / (packetlength * 8U)) * 10U) / pHI2s->Init.AudioFreq)) + 5U);
            }
        }
        else
        {
            /* MCLK output is disabled */
            tmp = (uint32_t)(((((i2sclk / packetlength) * 10U) / pHI2s->Init.AudioFreq)) + 5U);
        }

        /* Remove the flatting point */
        tmp = tmp / 10U;

        /* Check the parity of the divider, and compute the i2sdiv prescaler */
        i2sodd = (uint32_t)(tmp & (uint32_t)1U);
        i2sdiv = (uint32_t)((tmp - i2sodd) / 2U);

        /* Get the Mask for the Odd bit (SPI_I2SPR[8]) register */
        i2sodd = (uint32_t)(i2sodd << 8U);
    }

    /* Test if the divider is 1 or 0 or greater than 0xFF, set the error code */
    if ((i2sdiv < 2U) || (i2sdiv > 0xFFU))
    {
        SET_BIT(pHI2s->ErrorCode, HAL_I2S_ERROR_PRESCALER);
        return  HAL_ERROR;
    }

    /* SPIx I2SCFGR & I2SPR Configuration */
    pHI2s->Instance->I2SPR = (uint32_t)((uint32_t)i2sdiv | (uint32_t)(i2sodd | (uint32_t)pHI2s->Init.MCLKOutput));

    MODIFY_REG(pHI2s->Instance->I2SCFGR, (SPI_I2SCFGR_CHLEN | SPI_I2SCFGR_DATLEN | \
                                       SPI_I2SCFGR_CKPOL | SPI_I2SCFGR_I2SSTD | \
                                       SPI_I2SCFGR_PCMSYNC | SPI_I2SCFGR_I2SCFG | \
                                       SPI_I2SCFGR_I2SE  | SPI_I2SCFGR_I2SMOD), \
                    (SPI_I2SCFGR_I2SMOD | pHI2s->Init.Mode | \
                    pHI2s->Init.Standard | pHI2s->Init.DataFormat | \
                    pHI2s->Init.CPOL));

    pHI2s->ErrorCode = HAL_I2S_ERROR_NONE;
    pHI2s->State     = HAL_I2S_STATE_READY;

    return HAL_OK;
}

/**
  * @brief DeInitializes the I2S peripheral
  * @param  pHI2s pointer to a I2S_HandleTypeDef structure that contains
  *         the configuration information for I2S module
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_I2S_DeInit(I2S_HandleTypeDef *pHI2s)
{
    if (!pHI2s)
        return HAL_ERROR;

    assert_param(IS_I2S_ALL_INSTANCE(pHI2s->Instance));

    pHI2s->State = HAL_I2S_STATE_BUSY;

    /* Disable the I2S */
    CLEAR_BIT(pHI2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE);

    HAL_I2S_MspDeInit(pHI2s);

    pHI2s->ErrorCode = HAL_I2S_ERROR_NONE;
    pHI2s->State     = HAL_I2S_STATE_RESET;

    __HAL_UNLOCK(pHI2s);

    return HAL_OK;
}

/**
  * @brief  HAL_I2S_Transmit
  *             Transmit an amount of data in blocking mode
  * @param  [in] pHI2s       Pointer to a I2S_HandleTypeDef structure that contains
  *                         the configuration information for the specified I2S
  * @param  [in] pData      Pointer to data buffer
  * @param  [in] Size       Amount of data to be sent
  * @param  [in] Timeout    Timeout duration
  * @return HAL status
  */
HAL_StatusTypeDef HAL_I2S_Transmit(I2S_HandleTypeDef *pHI2s, uint16_t *pData, uint16_t Size, uint32_t Timeout)
{
    HAL_StatusTypeDef rval = HAL_OK;
    uint32_t reg_cfgr = 0;

    if (!pData || !Size )
        return  HAL_ERROR;

    if (pHI2s->State != HAL_I2S_STATE_READY)
        return HAL_BUSY;

    __HAL_LOCK(pHI2s);

    pHI2s->State = HAL_I2S_STATE_BUSY_TX;
    pHI2s->ErrorCode = HAL_I2S_ERROR_NONE;
    pHI2s->pTxBuffPtr = pData;

    reg_cfgr = pHI2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);

    if ((reg_cfgr == I2S_DATAFORMAT_24B) || (reg_cfgr == I2S_DATAFORMAT_32B))
    {
        pHI2s->TxXferSize = (Size << 1U);
        pHI2s->TxXferCount = (Size << 1U);
    }
    else
    {
        pHI2s->TxXferSize = Size;
        pHI2s->TxXferCount = Size;
    }

    reg_cfgr = pHI2s->Instance->I2SCFGR;

    /* Check if the I2S is already enabled. If not, enable I2S */
    if ((pHI2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SE) != SPI_I2SCFGR_I2SE)
    {
        SET_BIT(pHI2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE);
    }

    /* Wait until TXE flag is set */
    rval = _I2S_WaitFlagStateUntilTimeout(pHI2s, I2S_FLAG_TXE, SET, Timeout);
    if ( rval == HAL_TIMEOUT)
    {
        SET_BIT(pHI2s->ErrorCode, HAL_I2S_ERROR_TIMEOUT);
        pHI2s->State = HAL_I2S_STATE_READY;
        __HAL_UNLOCK(pHI2s);
        return HAL_ERROR;
    }

    while (pHI2s->TxXferCount > 0U)
    {
        pHI2s->Instance->DR = (*pHI2s->pTxBuffPtr);
        pHI2s->pTxBuffPtr++;
        pHI2s->TxXferCount--;

        /* Wait until TXE flag is set */
        rval = _I2S_WaitFlagStateUntilTimeout(pHI2s, I2S_FLAG_TXE, SET, Timeout);
        if (rval == HAL_TIMEOUT)
        {
            SET_BIT(pHI2s->ErrorCode, HAL_I2S_ERROR_TIMEOUT);
            pHI2s->State = HAL_I2S_STATE_READY;
            __HAL_UNLOCK(pHI2s);
            return HAL_ERROR;
        }

        /* Check if an underrun occurs */
        if (__HAL_I2S_GET_FLAG(pHI2s, I2S_FLAG_UDR) == SET)
        {
            __HAL_I2S_CLEAR_UDRFLAG(pHI2s);
            SET_BIT(pHI2s->ErrorCode, HAL_I2S_ERROR_UDR);
        }
    }

    /* Check if Slave mode is selected ,Wait until Busy flag is reset*/
    rval = _I2S_WaitFlagStateUntilTimeout(pHI2s, I2S_FLAG_BSY, RESET, Timeout);
    if ((((reg_cfgr & SPI_I2SCFGR_I2SCFG) == I2S_MODE_SLAVE_TX)
        || ((reg_cfgr & SPI_I2SCFGR_I2SCFG) == I2S_MODE_SLAVE_RX))
        && rval == HAL_TIMEOUT)
    {
        SET_BIT(pHI2s->ErrorCode, HAL_I2S_ERROR_TIMEOUT);
        pHI2s->State = HAL_I2S_STATE_READY;
        __HAL_UNLOCK(pHI2s);
        return HAL_ERROR;
    }

    pHI2s->State = HAL_I2S_STATE_READY;
    __HAL_UNLOCK(pHI2s);
    return HAL_OK;
}

/**
  * @brief  HAL_I2S_Receive
  *             Receive an amount of data in blocking mode
  * @param  [in] pHI2s       Pointer to a I2S_HandleTypeDef structure that contains
  *                         the configuration information for the specified I2S
  * @param  [in] pData      Pointer to data buffer
  * @param  [in] Size       Amount of data to be received
  * @param  [in] Timeout    Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_I2S_Receive(I2S_HandleTypeDef *pHI2s, uint16_t *pData, uint16_t Size, uint32_t Timeout)
{
    HAL_StatusTypeDef rval = HAL_OK;
    uint32_t reg_cfgr = 0;

    if (!pData || !Size )
        return  HAL_ERROR;

    if (pHI2s->State != HAL_I2S_STATE_READY)
        return HAL_BUSY;

    __HAL_LOCK(pHI2s);

    pHI2s->State = HAL_I2S_STATE_BUSY_RX;
    pHI2s->ErrorCode = HAL_I2S_ERROR_NONE;
    pHI2s->pRxBuffPtr = pData;

    reg_cfgr = pHI2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);
    if ((reg_cfgr == I2S_DATAFORMAT_24B) || (reg_cfgr == I2S_DATAFORMAT_32B))
    {
        pHI2s->RxXferSize = (Size << 1U);
        pHI2s->RxXferCount = (Size << 1U);
    }
    else
    {
        pHI2s->RxXferSize = Size;
        pHI2s->RxXferCount = Size;
    }

    /* Check if the I2S is already enabled. If not, enable I2S */
    if ((pHI2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SE) != SPI_I2SCFGR_I2SE)
    {
        SET_BIT(pHI2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE);
    }

    /* Check if Master Receiver mode is selected */
    if ((pHI2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_MASTER_RX)
    {
        __HAL_I2S_CLEAR_OVRFLAG(pHI2s);
    }

    /* Receive data */
    while (pHI2s->RxXferCount > 0U)
    {
        /* Wait until RXNE flag is set */
        rval = _I2S_WaitFlagStateUntilTimeout(pHI2s, I2S_FLAG_RXNE, SET, Timeout);
        if (rval == HAL_TIMEOUT)
        {
            SET_BIT(pHI2s->ErrorCode, HAL_I2S_ERROR_TIMEOUT);
            pHI2s->State = HAL_I2S_STATE_READY;
            __HAL_UNLOCK(pHI2s);
            return HAL_ERROR;
        }

        (*pHI2s->pRxBuffPtr) = (uint16_t)pHI2s->Instance->DR;
        pHI2s->pRxBuffPtr++;
        pHI2s->RxXferCount--;

        /* Check if an overrun occurs */
        if (__HAL_I2S_GET_FLAG(pHI2s, I2S_FLAG_OVR) == SET)
        {
            __HAL_I2S_CLEAR_OVRFLAG(pHI2s);
            SET_BIT(pHI2s->ErrorCode, HAL_I2S_ERROR_OVR);
        }
    }

    pHI2s->State = HAL_I2S_STATE_READY;
    __HAL_UNLOCK(pHI2s);
    return HAL_OK;
}

/**
  * @brief  HAL_I2S_Transmit_IT
  *             Transmit an amount of data in non-blocking mode with Interrupt
  * @param  [in] pHI2s       Pointer to a I2S_HandleTypeDef structure that contains
  *                         the configuration information for the specified I2S
  * @param  [in] pData      Pointer to data buffer
  * @param  [in] Size       Amount of data to be sent
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_I2S_Transmit_IT(I2S_HandleTypeDef *pHI2s, uint16_t *pData, uint16_t Size)
{
    uint32_t reg_cfgr = 0;

    if (!pData || !Size )
        return  HAL_ERROR;

    if (pHI2s->State != HAL_I2S_STATE_READY)
        return HAL_BUSY;

    __HAL_LOCK(pHI2s);

    pHI2s->State = HAL_I2S_STATE_BUSY_TX;
    pHI2s->ErrorCode = HAL_I2S_ERROR_NONE;
    pHI2s->pTxBuffPtr = pData;

    reg_cfgr = pHI2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);
    if ((reg_cfgr == I2S_DATAFORMAT_24B) || (reg_cfgr == I2S_DATAFORMAT_32B))
    {
        pHI2s->TxXferSize = (Size << 1U);
        pHI2s->TxXferCount = (Size << 1U);
    }
    else
    {
        pHI2s->TxXferSize = Size;
        pHI2s->TxXferCount = Size;
    }

    /* Enable TXE and ERR interrupt */
    SET_BIT(pHI2s->Instance->CR2,I2S_IT_TXE | I2S_IT_ERR);

    /* Check if the I2S is already enabled. If not, enable I2S*/
    if ((pHI2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SE) != SPI_I2SCFGR_I2SE)
    {
        SET_BIT(pHI2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE);
    }

    __HAL_UNLOCK(pHI2s);
    return HAL_OK;
}

/**
  * @brief  HAL_I2S_Receive_IT
  *             Receive an amount of data in non-blocking mode with Interrupt
  * @param  [in] pHI2s       Pointer to a I2S_HandleTypeDef structure that contains
  *                         the configuration information for the specified I2S
  * @param  [in] pData      Pointer to data buffer
  * @param  [in] Size       Amount of data to be receive
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_I2S_Receive_IT(I2S_HandleTypeDef *pHI2s, uint16_t *pData, uint16_t Size)
{
    uint32_t reg_cfgr = 0;

    if (!pData || !Size )
        return  HAL_ERROR;

    if (pHI2s->State != HAL_I2S_STATE_READY)
        return HAL_BUSY;

    __HAL_LOCK(pHI2s);

    pHI2s->State = HAL_I2S_STATE_BUSY_RX;
    pHI2s->ErrorCode = HAL_I2S_ERROR_NONE;
    pHI2s->pRxBuffPtr = pData;

    reg_cfgr = pHI2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);

    if ((reg_cfgr == I2S_DATAFORMAT_24B) || (reg_cfgr == I2S_DATAFORMAT_32B))
    {
        pHI2s->RxXferSize = (Size << 1U);
        pHI2s->RxXferCount = (Size << 1U);
    }
    else
    {
        pHI2s->RxXferSize = Size;
        pHI2s->RxXferCount = Size;
    }

    /* Enable RXNE and ERR interrupt */
    SET_BIT(pHI2s->Instance->CR2,I2S_IT_RXNE | I2S_IT_ERR);

    /* Check if the I2S is already enabled. If not, enable I2S */
    if ((pHI2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SE) != SPI_I2SCFGR_I2SE)
    {
        SET_BIT(pHI2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE);
    }

    __HAL_UNLOCK(pHI2s);
    return HAL_OK;
}


/**
  * @brief  HAL_I2S_Transmit_DMA
  *             Transmit an amount of data in non-blocking mode with DMA.
  * @param  [in] pHI2s          Pointer to a I2S_HandleTypeDef structure that contains
  *                             the configuration information for I2S module.
  * @param  [in] pData          Pointer to data buffer
  * @param  [in] Size           Amount of data to be sent
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_I2S_Transmit_DMA(I2S_HandleTypeDef *pHI2s, uint16_t *pData, uint16_t Size)
{
    uint32_t      tmpreg_cfgr;
    HAL_DMA_Descriptor_Cfg_TypeDef  desc_cfg;
    if ((!pData) || (!Size))
        return  HAL_ERROR;

    __HAL_LOCK(pHI2s);

    if (pHI2s->State != HAL_I2S_STATE_READY)
    {
        __HAL_UNLOCK(pHI2s);
        return HAL_BUSY;
    }

    /* Set state and reset error code */
    pHI2s->State = HAL_I2S_STATE_BUSY_TX;
    pHI2s->ErrorCode = HAL_I2S_ERROR_NONE;
    pHI2s->pTxBuffPtr = pData;

    tmpreg_cfgr = pHI2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);

    if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B))
    {
        pHI2s->TxXferSize = (Size << 1U);
        pHI2s->TxXferCount = (Size << 1U);
    }
    else
    {
        pHI2s->TxXferSize = Size;
        pHI2s->TxXferCount = Size;
    }

    /* Enable the Tx DMA Channel */
    desc_cfg.type       = DMA_DESCRIPTOR_TYPE_PRIMARY;
    desc_cfg.mode       = HAL_DMA_Mode_STOP;
    desc_cfg.src_addr   = (void *)(uint32_t)pData;
    desc_cfg.dst_addr   = (void *)&(pHI2s->Instance->DR);
    desc_cfg.xfer_bytes = pHI2s->TxXferSize * 2;

    desc_cfg.src_inc    = DMA_DATA_INC_HALFWORD;
    desc_cfg.dst_inc    = DMA_DATA_INC_NONE;
    desc_cfg.unit_size  = DMA_DATA_SIZE_HALFWORD;
    desc_cfg.arbit_rate = DMA_ARBITRATION_RATE_1;
    desc_cfg.timeout    = -1;

    if (HAL_OK != _I2S_DMA_Config(pHI2s->pHDMA, HAL_DMA_CHANNEL_SPI_I2S_TX,&desc_cfg))
    {
        SET_BIT(pHI2s->ErrorCode, HAL_I2S_ERROR_DMA);
        pHI2s->State = HAL_I2S_STATE_READY;
        __HAL_UNLOCK(pHI2s);
        return HAL_ERROR;
    }

    /* Check if the I2S is already enabled */
    if (HAL_IS_BIT_CLR(pHI2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE))
    {
        SET_BIT(pHI2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE);
    }

    /* Check if the I2S Tx request is already enabled */
    if (HAL_IS_BIT_CLR(pHI2s->Instance->CR2, SPI_CR2_TXDMAEN))
    {
        /* Enable Tx DMA Request */
        SET_BIT(pHI2s->Instance->CR2, SPI_CR2_TXDMAEN);
    }

    __HAL_UNLOCK(pHI2s);
    return HAL_OK;
}

/**
  * @brief  HAL_I2S_Receive_DMA
  *             Receive an amount of data in non-blocking mode with DMA.
  * @param  [in] pHI2s          Pointer to a I2S_HandleTypeDef structure that contains
  *                             the configuration information for I2S module.
  * @param  [in] pData          Pointer to data buffer
  * @param  [in] Size           Amount of data to be received
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_I2S_Receive_DMA(I2S_HandleTypeDef *pHI2s, uint16_t *pData, uint16_t Size)
{
    uint32_t    tmpreg_cfgr;
    HAL_DMA_Descriptor_Cfg_TypeDef  desc_cfg;

    if ((!pData) || (!Size))
        return  HAL_ERROR;

    __HAL_LOCK(pHI2s);

    if (pHI2s->State != HAL_I2S_STATE_READY)
    {
        __HAL_UNLOCK(pHI2s);
        return HAL_BUSY;
    }

    /* Set state and reset error code */
    pHI2s->State = HAL_I2S_STATE_BUSY_RX;
    pHI2s->ErrorCode = HAL_I2S_ERROR_NONE;
    pHI2s->pRxBuffPtr = pData;

    tmpreg_cfgr = pHI2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);

    if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B))
    {
        pHI2s->RxXferSize = (Size << 1U);
        pHI2s->RxXferCount = (Size << 1U);
    }
    else
    {
        pHI2s->RxXferSize = Size;
        pHI2s->RxXferCount = Size;
    }

    /* Check if Master Receiver mode is selected */
    if (pHI2s->Init.Mode == I2S_MODE_MASTER_RX)
    {
        __HAL_I2S_CLEAR_OVRFLAG(pHI2s);
        CLEAR_BIT(pHI2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SCFG);
        SET_BIT(pHI2s->Instance->I2SCFGR, I2S_MODE_MASTER_TX);
        __HAL_I2S_FULL_DUPLEX_ENABLE(pHI2s);

        pHI2s->pTxBuffPtr = pData;
        pHI2s->TxXferSize = pHI2s->RxXferSize;
        pHI2s->TxXferCount = pHI2s->RxXferCount;

         /* Enable the Tx DMA Channel */
        desc_cfg.type       = DMA_DESCRIPTOR_TYPE_PRIMARY;
        desc_cfg.mode       = HAL_DMA_Mode_STOP;
        desc_cfg.src_addr   = (void *)(uint32_t)pData;
        desc_cfg.dst_addr   = (void *)&(pHI2s->Instance->DR);
        desc_cfg.xfer_bytes = pHI2s->TxXferSize * 2;

        desc_cfg.src_inc    = DMA_DATA_INC_HALFWORD;
        desc_cfg.dst_inc    = DMA_DATA_INC_NONE;
        desc_cfg.unit_size  = DMA_DATA_SIZE_HALFWORD;
        desc_cfg.arbit_rate = DMA_ARBITRATION_RATE_1;
        desc_cfg.timeout    = -1;

        if (HAL_OK != _I2S_DMA_Config(pHI2s->pHDMA, HAL_DMA_CHANNEL_SPI_I2S_TX,&desc_cfg))
        {
            SET_BIT(pHI2s->ErrorCode, HAL_I2S_ERROR_DMA);
            pHI2s->State = HAL_I2S_STATE_READY;
            __HAL_UNLOCK(pHI2s);
            return HAL_ERROR;
        }
    }

    /* Enable the Rx DMA Channel */
    desc_cfg.type       = DMA_DESCRIPTOR_TYPE_PRIMARY;
    desc_cfg.mode       = HAL_DMA_Mode_STOP;
    desc_cfg.src_addr   = (void *)&(pHI2s->Instance->DR);
    desc_cfg.dst_addr   = pData;
    desc_cfg.xfer_bytes = pHI2s->RxXferSize * 2;

    desc_cfg.src_inc    = DMA_DATA_INC_NONE;
    desc_cfg.dst_inc    = DMA_DATA_INC_HALFWORD;
    desc_cfg.unit_size  = DMA_DATA_SIZE_HALFWORD;
    desc_cfg.arbit_rate = DMA_ARBITRATION_RATE_1;
    desc_cfg.timeout    = -1;

    if (HAL_OK != _I2S_DMA_Config(pHI2s->pHDMA, HAL_DMA_CHANNEL_SPI_I2S_RX,&desc_cfg))
    {
        SET_BIT(pHI2s->ErrorCode, HAL_I2S_ERROR_DMA);
        pHI2s->State = HAL_I2S_STATE_READY;
        __HAL_UNLOCK(pHI2s);
        return HAL_ERROR;
    }

    /* Check if the I2S is already enabled */
    if (HAL_IS_BIT_CLR(pHI2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE))
    {
        /* Enable I2S peripheral */
        SET_BIT(pHI2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE);
    }

    /* Check if the I2S Rx request is already enabled */
    if (HAL_IS_BIT_CLR(pHI2s->Instance->CR2, SPI_CR2_RXDMAEN))
    {
        /* Enable Rx DMA Request */
        SET_BIT(pHI2s->Instance->CR2, SPI_CR2_RXDMAEN);
    }

    if ((pHI2s->Init.Mode == I2S_MODE_MASTER_RX) &&
         HAL_IS_BIT_CLR(pHI2s->Instance->CR2, SPI_CR2_TXDMAEN))
    {
        /* Enable Tx DMA Request */
        SET_BIT(pHI2s->Instance->CR2, SPI_CR2_TXDMAEN);
    }

    __HAL_UNLOCK(pHI2s);
    return HAL_OK;
}

/**
  * @brief  HAL_I2S_DMAPause
  *             Pauses the audio DMA Channel
  * @param  [in] pHI2s      Pointer to a I2S_HandleTypeDef structure that contains
  *                         the configuration information for I2S module
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_I2S_DMAPause(I2S_HandleTypeDef *pHI2s)
{
    __HAL_LOCK(pHI2s);

    /* Disable the I2S DMA Tx/Rx request */
    if (pHI2s->State == HAL_I2S_STATE_BUSY_TX)
    {
        CLEAR_BIT(pHI2s->Instance->CR2, SPI_CR2_TXDMAEN);
    }
    else if (pHI2s->State == HAL_I2S_STATE_BUSY_RX)
    {
        CLEAR_BIT(pHI2s->Instance->CR2, SPI_CR2_RXDMAEN);
    }

    __HAL_UNLOCK(pHI2s);

    return HAL_OK;
}

/**
  * @brief  HAL_I2S_DMAResume
  *             Resumes the audio DMA Channel
  * @param  [in] pHI2s      Pointer to a I2S_HandleTypeDef structure that contains
  *                         the configuration information for I2S module
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_I2S_DMAResume(I2S_HandleTypeDef *pHI2s)
{
    __HAL_LOCK(pHI2s);

    /* Enable the I2S DMA Tx/Rx request */
    if (pHI2s->State == HAL_I2S_STATE_BUSY_TX)
    {
        SET_BIT(pHI2s->Instance->CR2, SPI_CR2_TXDMAEN);
    }
    else if (pHI2s->State == HAL_I2S_STATE_BUSY_RX)
    {
        SET_BIT(pHI2s->Instance->CR2, SPI_CR2_RXDMAEN);
    }

    /* If the I2S peripheral is still not enabled, enable it */
    if (HAL_IS_BIT_CLR(pHI2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE))
    {
        SET_BIT(pHI2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE);
    }

    __HAL_UNLOCK(pHI2s);

    return HAL_OK;
}

/**
  * @brief  HAL_I2S_DMAStop
  *             Stops the DMA Channel
  * @param  [in] pHI2s      Pointer to a I2S_HandleTypeDef structure that contains
  *                         the configuration information for I2S module
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_I2S_DMAStop(I2S_HandleTypeDef *pHI2s)
{
    HAL_StatusTypeDef errorcode = HAL_OK;

    if ((pHI2s->Init.Mode == I2S_MODE_MASTER_TX) || (pHI2s->Init.Mode == I2S_MODE_SLAVE_TX))
    {
        if (pHI2s->pHDMA != NULL)
        {
            /* Disable the I2S DMA tx Channel */
            if (HAL_OK != HAL_DMA_Channel_Stop(pHI2s->pHDMA, HAL_DMA_CHANNEL_SPI_I2S_TX))
            {
                SET_BIT(pHI2s->ErrorCode, HAL_I2S_ERROR_DMA);
                errorcode = HAL_ERROR;
            }
        }

        /* Disable the I2S Tx DMA requests */
        CLEAR_BIT(pHI2s->Instance->CR2, SPI_CR2_TXDMAEN);
    }

    else if ((pHI2s->Init.Mode == I2S_MODE_MASTER_RX) || (pHI2s->Init.Mode == I2S_MODE_SLAVE_RX))
    {
        if (pHI2s->pHDMA != NULL)
        {
            /* Disable the I2S DMA rx Channel */
            if (HAL_OK != HAL_DMA_Channel_Stop(pHI2s->pHDMA, HAL_DMA_CHANNEL_SPI_I2S_RX))
            {
                SET_BIT(pHI2s->ErrorCode, HAL_I2S_ERROR_DMA);
                errorcode = HAL_ERROR;
            }
        }

        /* Disable the I2S Rx DMA request */
        CLEAR_BIT(pHI2s->Instance->CR2, SPI_CR2_RXDMAEN);
    }

    pHI2s->State = HAL_I2S_STATE_READY;

    return errorcode;
}
/**
  * @brief  This function handles I2S interrupt request.
  * @param  [in] pHI2s   Pointer to a I2S_HandleTypeDef structure that contains
  *                     the configuration information for the specified I2S
  * @retval None
  */
void HAL_I2S_IRQHandler(I2S_HandleTypeDef *pHI2s)
{
    uint32_t itsource = pHI2s->Instance->CR2;
    uint32_t itflag   = pHI2s->Instance->SR;

    /* I2S in mode Receiver */
    if ((I2S_CHECK_FLAG(itflag, I2S_FLAG_OVR) == RESET) &&
        (I2S_CHECK_FLAG(itflag, I2S_FLAG_RXNE) != RESET) &&
        (I2S_CHECK_IT_SOURCE(itsource, I2S_IT_RXNE) != RESET))
    {
        _I2S_Receive_IT(pHI2s);
        return;
    }

    /* I2S in mode Tramitter */
    if ((I2S_CHECK_FLAG(itflag, I2S_FLAG_TXE) != RESET) &&
        (I2S_CHECK_IT_SOURCE(itsource, I2S_IT_TXE) != RESET))
    {
        _I2S_Transmit_IT(pHI2s);
        return;
    }

    /* I2S interrupt error */
    if (I2S_CHECK_IT_SOURCE(itsource, I2S_IT_ERR) != RESET)
    {
        /* I2S Overrun error interrupt occurred, disable RXNE and ERR interrupt.*/
        if (I2S_CHECK_FLAG(itflag, I2S_FLAG_OVR) != RESET)
        {
            CLEAR_BIT(pHI2s->Instance->CR2,I2S_IT_RXNE | I2S_IT_ERR);
            SET_BIT(pHI2s->ErrorCode, HAL_I2S_ERROR_OVR);
        }

        /* I2S Underrun error interrupt occurred , disable TXE and ERR interrupt*/
        if (I2S_CHECK_FLAG(itflag, I2S_FLAG_UDR) != RESET)
        {
            CLEAR_BIT(pHI2s->Instance->CR2,I2S_IT_TXE | I2S_IT_ERR);
            SET_BIT(pHI2s->ErrorCode, HAL_I2S_ERROR_UDR);
        }

        pHI2s->State = HAL_I2S_STATE_READY;

        HAL_I2S_ErrorCallback(pHI2s);
    }
}

/**
  * @brief  Initializes the I2S MSP
  * @param  pHI2s : I2S handle
  * @retval None
  */
__weak void HAL_I2S_MspInit(I2S_HandleTypeDef *pHI2s)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHI2s);
}

/**
  * @brief  DeInitializes the I2S MSP
  * @param  pHI2s : I2S handle
  * @retval None
  */
__weak void HAL_I2S_MspDeInit(I2S_HandleTypeDef *pHI2s)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHI2s);
}

/**
  * @brief  Tx Transfer completed callbacks
  * @param  pHI2s : I2S handle
  * @retval None
  */
__weak void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *pHI2s)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHI2s);
}

/**
  * @brief  Rx Transfer completed callbacks
  * @param  pHI2s : I2S handle
  * @retval None
  */
__weak void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *pHI2s)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHI2s);
}

/**
  * @brief  I2S error callbacks
  * @param  pHI2s : I2S handle
  * @retval None
  */
__weak void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *pHI2s)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHI2s);
}

/**
  * @brief  Return the I2S state
  * @param  pHI2s : I2S handle
  * @retval HAL state
  */
HAL_I2S_StateTypeDef HAL_I2S_GetState(I2S_HandleTypeDef *pHI2s)
{
    return pHI2s->State;
}

/**
  * @brief  Return the I2S error code
  * @param  pHI2s : I2S handle
  * @retval I2S Error Code
  */
uint32_t HAL_I2S_GetError(I2S_HandleTypeDef *pHI2s)
{
    return pHI2s->ErrorCode;
}



/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

#endif /* HAL_I2S_MODULE_ENABLED */
